/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.core;
import java.util.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeSupport;
import org.openide.TopManager;
import org.openide.filesystems.FileSystem;
import org.openide.filesystems.FileStateInvalidException;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileChangeAdapter;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.RepositoryListener;
import org.openide.filesystems.RepositoryEvent;
import org.openide.filesystems.RepositoryReorderedEvent;
import org.openide.loaders.DataFilter;
import org.openide.loaders.DataFolder;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.loaders.DataLoaderPool;
import org.openide.nodes.FilterNode;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Node;
import org.openide.nodes.Children;
import org.openide.nodes.Children.SortedMap;
import org.openide.nodes.NodeAdapter;
import org.openide.util.WeakListener;
import org.openide.util.enum.AlterEnumeration;
import org.openide.util.enum.EmptyEnumeration;
import org.openide.util.enum.SingletonEnumeration;
import org.openide.util.enum.SequenceEnumeration;
/** Children that contains list of packages in repository.
*
* @author Jaroslav Tulach, Jan Jancura
*/
final class PackageChildren extends Children.Keys
implements PropertyChangeListener {
/** filters which hides folders */
private static final DataFilter DATA_FILTER = new NoFolderFilter ();
/** Current DataFilter */
private DataFilter dataFilter;
/** holder of all packages */
private Packages packages;
/** weak listener */
private PropertyChangeListener weakPCL;
// init ..............................................................................
/** Creates a package node for given filter.
* @param f the filter to use
*/
public static Node createNode (DataFilter f) {
return new AbstractNode (new PackageChildren (f));
}
/**
* Create PackageChildren with given filter.
*/
private PackageChildren (DataFilter dataFilter) {
this.dataFilter = dataFilter;
}
/* Ask for list of packages
*/
protected void addNotify () {
packages = Packages.getDefault ();
weakPCL = WeakListener.propertyChange (this, packages);
packages.addPropertyChangeListener (weakPCL);
packages.update (this);
}
/** Clear all nodes */
protected void removeNotify () {
setKeys (java.util.Collections.EMPTY_SET);
packages.removePropertyChangeListener (weakPCL);
packages = null;
weakPCL = null;
}
public void propertyChange(final java.beans.PropertyChangeEvent p1) {
if (Packages.PROP_LIST.equals (p1.getPropertyName ())) {
Packages p = packages;
if (p != null) {
p.update (this);
}
return;
}
if (Packages.PROP_NAME.equals (p1.getPropertyName ())) {
if (isInitialized ()) {
Children.MUTEX.readAccess (new Runnable () {
public void run () {
FileObject changed = (FileObject)p1.getNewValue ();
Node[] arr = getNodes ();
for (int i = 0; i < arr.length; i++) {
DataFolder df = (DataFolder)arr[i].getCookie (DataFolder.class);
if (df != null && subfolder (changed, df.getPrimaryFile ())) {
arr[i].setDisplayName (df.getPrimaryFile ().getPackageName ('.'));
}
}
}
});
}
}
}
/** Test whether one file object is subfile of another.
* @param folder the folder
* @param subfile the subfile
* @return true if folder contains subfile
*/
private static boolean subfolder (FileObject folder, FileObject subfile) {
for (;;) {
if (subfile == null) return false;
if (subfile.equals (folder)) return true;
subfile = subfile.getParent ();
}
}
/** Callback method from Packages class when it is safe to update
* packages.
*/
public void updatePackages (TreeSet set) {
if (dataFilter == DataFilter.ALL) {
// use whole set
setKeys (set);
} else {
// filter some nodes
LinkedList ll = new LinkedList ();
Iterator it = set.iterator ();
while (it.hasNext ()) {
FileObject fo = (FileObject)it.next ();
try {
DataObject obj = DataObject.find (fo);
if (dataFilter.acceptDataObject (obj)) {
ll.add (fo);
}
} catch (DataObjectNotFoundException ex) {
// ignore
}
}
setKeys (ll);
}
}
/** Create children for a data-object key.
* If {@link ElementCookie} is provided, then the proxy node's children
* are used for this node's children (for this key), after possible filtering
* based on the {@link #putFilter current filters}.
* If <code>ElementCookie</code> is not provided, then
* (a copy of) this data's object's delegate node is used as the sole child
* for this key.
* @param key a {@link DataObject} to create representative children for
* @return a list of child nodes for this key
*/
protected Node[] createNodes (Object key) {
FileObject fo = (FileObject) key;
try {
DataObject obj = DataObject.find (fo);
if (obj instanceof DataFolder) {
DataFolder df = (DataFolder)obj;
DataFilter filter =
dataFilter == DataFilter.ALL ? DATA_FILTER : dataFilter;
Node n;
if (fo.isRoot ()) {
n = new RootFolderNode (
df, df.createNodeChildren (filter)
);
} else {
DataFolder.FolderNode fn = df.new FolderNode (
df.createNodeChildren (filter)
);
fn.setDisplayName (df.getPrimaryFile ().getPackageName ('.'));
n = fn;
}
return new Node[] { n };
}
} catch (DataObjectNotFoundException ee) {
}
return new Node[] {};
}
/** DataFilter that (does not) accepts data folders.
*/
private static final class NoFolderFilter extends Object
implements DataFilter {
/** Should the data object be displayed or not?
* @param obj the data object
* @return <CODE>true</CODE> if the object should be displayed,
* <CODE>false</CODE> otherwise
*/
public boolean acceptDataObject (DataObject obj) {
return ! (obj instanceof DataFolder);
}
}
}
/*
* Log
* 3 Gandalf 1.2 1/9/00 Jaroslav Tulach Renaming works better.
* 2 Gandalf 1.1 11/29/99 Jaroslav Tulach Deleted PNode inner class
* 1 Gandalf 1.0 11/29/99 Jaroslav Tulach
* $
*/